import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User:岁亮亮
 * Date:2024-10-23
 * TIME:10:29
 */
public class UdpEchoServer {

    //先定义一个socket对象来操作网卡这样的网络设备收发数据
    private DatagramSocket socket = null;
    //服务器要手动指定一个固定的端口号 客户端才能知道要将数据发送到那里
    public UdpEchoServer(int port) throws SocketException {
        socket = new DatagramSocket(port);
    }

    public void start() throws IOException {
        System.out.println("服务器启动  ");
        //服务器启动 就是不断地等待接收客户端发来的请求 请做出响应
        //一般不会停止服务器 都是7*24小时随时待命
        while(true){
            //服务器处理请求的3步 流程
            //1 接收发来的请求
            //2. 根据请求 计算响应 (咱们这个是回显服务器 一般客户端发什么 服务器就返回什么 就是一个return就行了)
            //3.根据发来的请求得出客户端的IP 和端口 发送响应

            //1
            //DatagramPacket对象是作为收发数据的基本单位 看一看成UDP数据报 内部用字节数组存储UDP的载荷部分 其他属性存储请求的其他部分
            //socket对象接受的 请求 存储到DatagramPacket对象中即UDP数据报
            DatagramPacket requestPacket = new DatagramPacket(new byte[512],512);//相当于空的数据报
            //socket对象的receive()方法 就是网卡层接受的请求信息 经过上层 层层分用 ,解析出来的UDP数据报
            //放在socket的缓冲区中,receive()方法就是从这个缓冲区中取出UDP数据报 放到requestPacket对象中
            //缓冲区 可以看成之前学过的生产者-消费者模型 用阻塞队列组成
            //还有一点需要注意 服务器刚启动的时候 客户端还没有发来请求 socket缓冲区中没有UDP数据报 这时receive()就会进入阻塞状态 等待请求发过来
            socket.receive(requestPacket);

            //2
            //取出 载荷部分 即客户端应用层 要请求什么数据
            String request = new String(requestPacket.getData(),0, requestPacket.getLength());
            //根据请求做出响应
            String reponse = process(request);
            //发送请求  构造一个DatagramPacket 对象来作为发送单位 构造对象的时候我们知道要返回响应的内容是什么,就不用设置数组来构造对象
            //构造对象的时候 这个响应字符串reponse转换为数组作为发送给客户端应用层的响应,还要设置目的IP和目的端口才能发送给客户端
            //客户端发送过来的请求requestPacket对象中就包含了客户端的目的IP和目的端口.
            DatagramPacket reponsePacket = new DatagramPacket(reponse.getBytes(StandardCharsets.UTF_8),reponse.getBytes().length
                                                            , requestPacket.getSocketAddress());
            //这也就间接表明了UDP协议 在收发数据的过程中是没有建立连接 或者没有收到请求连接的 客户端的IP和端口值保存在发送过来的请求中即requestPacket对象中

            //3.
            socket.send(reponsePacket);
            System.out.printf("[%s : %d] rep : %s -> resp : %s \n",requestPacket.getAddress().toString(),requestPacket.getPort()
                                                               ,request,reponse);

        }
    }

    public static void main(String[] args) throws IOException {
        UdpEchoServer u = new UdpEchoServer(9090);
        u.start();

    }
    //回显服务器 直接返回客户端发过来的数据就行了 有需要可以自己添加代码逻辑
    private String process(String request) {
        return request;
    }

}
